package fxmedia;

// Import Java JDK Classes
import java.io.File;
import java.util.Arrays;

// Import JavaFX Classes
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;

// Import Apache Commons Classes
import org.apache.commons.io.FilenameUtils;

// Import JID3 Classes
import org.blinkenlights.jid3.MP3File;
import org.blinkenlights.jid3.v1.ID3V1Tag;

// Import Application classes
import fxmedia.ui.*;

/**
 * @author dca
 */
public class FxMedia extends Application {
	/** The music player.<br/> */
	private Player player;

	/** The library list UI control.<br/> */
	private LibraryList libraryList;

	/** The previous button UI control.<br/> */
	private PreviousButton prevTrackButton;

	/** The play button UI control.<br/> */
	private PlayButton playTrackButton;

	/** The next button UI control.<br/> */
	private NextButton nextTrackButton;

	/** The order tracks UI control.<br/> */
	private OrderButton orderTracksButton;

	/** The current track title text.<br/> */
	private TrackLabel currentTitle = new TrackLabel(true, false, false);

	/** The current track artist text.<br/> */
	private TrackLabel currentArtist = new TrackLabel(false, true, false);

	/** The current track album text.<br/> */
	private TrackLabel currentAlbum = new TrackLabel(false, false, true);

	/** The current track genre text.<br/> */
	private TrackLabel currentGenre = new TrackLabel(false, false, false);

	/** The current track album picture.<br/> */
	private ImageView currentAlbumArt = new ImageView();

	/**
	 * Returns the player field.<br/>
	 * @return player The media player.<br/>
	 */
	public Player getPlayer() {
		return player;
	} // END getPlayer

	/**
	 * Returns the library list field.<br/>
	 * @return libraryList The library list UI control.<br/>
	 */
	public LibraryList getLibraryList() {
		return libraryList;
	} // END getLibraryList

	/**
	 * Returns the previous button field.<br/>
	 * @return prevTrackButton The previous button UI control.<br/>
	 */
	public PreviousButton getPrevTrackButton() {
		return prevTrackButton;
	} // END getPrevTrackButton

	/**
	 * Returns the play button field.<br/>
	 * @return playTrackButton The play button UI control.<br/>
	 */
	public PlayButton getPlayTrackButton() {
		return playTrackButton;
	} // END getPlayTrackButton

	/**
	 * Returns the next button field.<br/>
	 * @return nextTrackButton The next button UI control.<br/>
	 */
	public NextButton getNextTrackButton() {
		return nextTrackButton;
	} // END getNextTrackButton

	/**
	 * Returns the order tracks field.<br/>
	 * @return orderTracksButton The order tracks UI control.<br/>
	 */
	public OrderButton getOrderTracksButton() {
		return orderTracksButton;
	} // END getOrderTracksButton

	/**
	 * Defines the scene and shows the stage.<br/>
	 * @param stage The stage to show.<br/>
	 */
	@Override
    public void start(final Stage stage) {
		String libraryPath = Constants.DEFAULT_MUSIC_LIBRARY_LOCATION;
		for(String param : getParameters().getUnnamed()) {
			libraryPath = param;
		} // END loop

		if(libraryPath.equalsIgnoreCase("gui")) {
			DirectoryChooser dc = new DirectoryChooser();
			libraryPath = dc.showDialog(stage).getAbsolutePath();
			System.out.printf("Loading Media Library: %s%n", libraryPath);
		} // END if

		player = new Player(libraryPath);
		libraryList = new LibraryList(this);

		Label libraryLabel = new Label(Constants.LIBRARY_LABEL);
        prevTrackButton = new PreviousButton(this);
        playTrackButton = new PlayButton(this);
        nextTrackButton = new NextButton(this);
        orderTracksButton = new OrderButton(this);

		AnchorPane anchorPane = new AnchorPane();
		GridPane playerControlPane = new GridPane();
		GridPane trackInfoPane = new GridPane();

		playerControlPane.setHgap(Constants.DEFAULT_PADDING);
		trackInfoPane.setHgap(Constants.DEFAULT_PADDING);

		int col = 1;
		int row = 1;
		playerControlPane.add(prevTrackButton,   col++, row); // column=1 row=1
		playerControlPane.add(playTrackButton,   col++, row); // column=2 row=1
		playerControlPane.add(nextTrackButton,   col++, row); // column=3 row=1
		playerControlPane.add(orderTracksButton, col++, row); // column=4 row=1

		col = 1;
		row = 1;
		trackInfoPane.add(new Label(Constants.TITLE_LABEL),  col, row++); // column=1 row=1
		trackInfoPane.add(new Label(Constants.ARTIST_LABEL), col, row++); // column=1 row=2
		trackInfoPane.add(new Label(Constants.ALBUM_LABEL),  col, row++); // column=1 row=3
		trackInfoPane.add(new Label(Constants.GENRE_LABEL),  col, row++); // column=1 row=4

		col++;
		row = 1;
		trackInfoPane.add(currentTitle,  col, row++); // column=2 row=1
		trackInfoPane.add(currentArtist, col, row++); // column=2 row=2
		trackInfoPane.add(currentAlbum,  col, row++); // column=2 row=3
		trackInfoPane.add(currentGenre,  col, row++); // column=2 row=4

		double topOffset = Constants.DEFAULT_PADDING;
		double leftOffset = Constants.DEFAULT_PADDING;
		anchorNode(libraryLabel,      topOffset,       null, null,                      leftOffset); // Set Library Label POSITION
		anchorNode(libraryList,       topOffset * 5d,  null, Constants.DEFAULT_PADDING, leftOffset); // Set Library List POSITION
		leftOffset += libraryList.getPrefWidth() + Constants.DEFAULT_PADDING;
		anchorNode(playerControlPane, topOffset,       null, null,                      leftOffset); // Set Player Controls POSITION
		anchorNode(trackInfoPane,     topOffset * 8d,  null, null,                      leftOffset); // Set Track Info POSITION
		leftOffset += Constants.DEFAULT_PADDING;
		anchorNode(currentAlbumArt,   topOffset * 22d, null, null,                      leftOffset); // Set Album Art POSITION

		anchorPane.getChildren().addAll(libraryLabel, libraryList, playerControlPane, trackInfoPane, currentAlbumArt);
        Scene scene = new Scene(anchorPane, Constants.STAGE_WIDTH, Constants.STAGE_HEIGHT);

        stage.setTitle(FxMedia.class.getSimpleName());
        stage.setScene(scene);
        stage.show();
	} // END start

	/**
	 * Anchors the node based on the four offsets.<br/>
	 * @param child The node to anchor.<br/>
	 * @param top The top offset.<br/>
	 * @param right The right offset.<br/>
	 * @param bottom The bottom offset.<br/>
	 * @param left The left offset.<br/>
	 */
	private void anchorNode(Node child, Double top, Double right, Double bottom, Double left) {
		if(null != child) {
			if(null != top)    AnchorPane.setTopAnchor(child,    top);
			if(null != right)  AnchorPane.setRightAnchor(child,  right);
			if(null != bottom) AnchorPane.setBottomAnchor(child, bottom);
			if(null != left)   AnchorPane.setLeftAnchor(child,   left);
		} // END if
	} // END anchorNode

	/**
	 * Updates the title, artist and album information from ID3 tags.<br/>
	 * @param mp3File The JID ID3 object.<br/>
	 */
	public void updateTrackInfo(final MP3File mp3File) {
		try {
			if(null != mp3File) {
				final ID3V1Tag tag = mp3File.getID3V1Tag();

				Platform.runLater(new Runnable() {
					@Override
					public void run() {
						currentTitle.setText(null != tag  ? tag.getTitle()            : "");
						currentArtist.setText(null != tag ? tag.getArtist()           : "");
						currentAlbum.setText(null != tag  ? tag.getAlbum()            : "");
						currentGenre.setText(null != tag  ? tag.getGenre().toString() : "");
					} // END run
				}); // END Runnable
			} // END if
	    } catch(Exception exc) {
			System.out.printf("ERROR: Error getting ID3 information: %s%n", exc.getMessage());
			exc.printStackTrace();
	    } // END try/catch
	} // END updateTrackInfo

	/**
	 * Updates the album artwork image view based on whether or not an image file is found in the same directory as the mp3.<br/>
	 * @param mediaFile The mp3 file.<br/>
	 */
	public void updateAlbumArt(final MediaFile mediaFile) {
		if(null != mediaFile) {
			for(final File file : mediaFile.getParentFile().listFiles()) {
				final String ext = FilenameUtils.getExtension(file.getAbsolutePath()).toLowerCase();
				if(Arrays.asList("jpg", "gif", "png").contains(ext)) {
					final String albumArtPath = Constants.FILE_PROTOCOL + file.getAbsolutePath();
					final Image albumArtImg = new Image(albumArtPath, 200d, 200d, true, true);
					currentAlbumArt.setImage(albumArtImg);
					break; // Stop looping after first image.
				} // END if
			} // END loop
		} // END if
	} // END updateAlbumArt

	/**
	 * Tests the class.<br/>
	 * @param args The command-line arguments.<br/>
	 *             One may be specified, to denote the location of media files.<br/>
	 */
	public static void main(String[] args) {
		Application.launch(FxMedia.class, args);
	} // END main
} // END class FxMedia
